package com.itheima.document.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.common.exception.NcException;
import com.itheima.common.exception.enums.ResponseEnum;
import com.itheima.common.threadlocal.UserHolder;
import com.itheima.common.util.BeanHelper;
import com.itheima.common.util.CountUtil;
import com.itheima.common.util.StringUtil;
import com.itheima.common.vo.PageResult;
import com.itheima.document.dto.*;
import com.itheima.document.entity.Collaborations;
import com.itheima.document.entity.DocFile;
import com.itheima.document.entity.DocFolder;
import com.itheima.document.entity.FileHistory;
import com.itheima.document.enums.DocumentEnum;
import com.itheima.sys.client.CompanyUserClient;
import com.itheima.sys.dto.CompanyUserDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DocumentService {


    @Autowired
    private IDocFileService docFileService;

    @Autowired
    private IDocFolderService docFolderService;

    @Autowired
    private IFileHistoryService fileHistoryService;

    @Autowired
    private ICollaborationsService collaborationsService;


    @Autowired
    private CompanyUserClient companyUserClient;
    private List<DocFile> privateFileList;


    /**
     * 分页查询文档列表
     *
     * @param page
     * @param pageSize
     * @param keyword
     * @return
     */
    public PageResult<DocFileDTO> queryFileList(Integer page, Integer pageSize, String keyword) {
        QueryWrapper<DocFile> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.lambda().like(DocFile::getName, keyword);
        }
        IPage<DocFile> iPage = new Page<>(page, pageSize);
        iPage = docFileService.page(iPage, queryWrapper);
        List<DocFile> docFileList = iPage.getRecords();
        //设置文档作者信息，写作者信息
        List<DocFileDTO> docFileDTOList = BeanHelper.copyWithCollection(docFileList, DocFileDTO.class);
        for (DocFileDTO docFileDTO : docFileDTOList) {
            //设置文档作者
            CompanyUserDTO companyUserDTO = companyUserClient.queryCompanyUserOne(docFileDTO.getCompanyUserId()).getData();
            docFileDTO.setCreator(companyUserDTO);

            //设置文档协作者
            //先根据文档ID 查询协作者 ID
            QueryWrapper<Collaborations> collaborationsQueryWrapper = new QueryWrapper<>();
            collaborationsQueryWrapper.lambda().eq(Collaborations::getFileId, docFileDTO.getId());
            List<Collaborations> collaborationsList = collaborationsService.list(collaborationsQueryWrapper);
            List<Long> companyUserIds = collaborationsList.stream().map(Collaborations::getCompanyUserId).collect(Collectors.toList());
            List<CompanyUserDTO> companyUserDTOList = companyUserClient.queryCompanyUserByIds(companyUserIds).getData();
            docFileDTO.setCollaborations(companyUserDTOList);
        }
        return new PageResult<>(iPage.getTotal(), iPage.getPages(), docFileDTOList);
    }

    public void updateEnable(Long fileId, Boolean enable) {
        //根据主键修改状态
        DocFile docFile = new DocFile();
        docFile.setId(fileId);
        docFile.setEnable(enable);
        boolean b = docFileService.updateById(docFile);
        if (!b) {
            throw new NcException(ResponseEnum.UPDATE_OPERATION_FAIL);
        }

    }

    public PageResult<FileHistoryDTO> queryEditHistoryByFileId(Long fileId, Integer page, Integer pageSize) {
        QueryWrapper<FileHistory> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(FileHistory::getFileId, fileId);
        IPage<FileHistory> ipage = fileHistoryService.page(new Page<>(page, pageSize), queryWrapper);
        if (!ipage.getRecords().isEmpty()) {
            List<FileHistoryDTO> fileHistoryDTOS = BeanHelper.copyWithCollection(ipage.getRecords(), FileHistoryDTO.class);
            for (FileHistoryDTO fileHistoryDTO : fileHistoryDTOS) {
                String username = companyUserClient.queryCompanyUserOne(fileHistoryDTO.getCompanyUserId()).getData().getUsername();
                fileHistoryDTO.setUsername(username);
            }

            return new PageResult<>(ipage.getTotal(), ipage.getPages(), fileHistoryDTOS);
        }
        return null;
    }

    /**
     * 移动端查询当前用户可见 文件夹以及文件
     *
     * @param folderAndFileDTO parentFoldId:上级文件夹ID  0：代表顶级文件夹
     * @return
     */
    public DocumentDTO queryFolderAndFile(FolderAndFileDTO folderAndFileDTO) {
        DocumentDTO documentDTO = new DocumentDTO();
        documentDTO.setFolders(this.queryCompanyFolder(folderAndFileDTO));
        documentDTO.setFiles(this.queryCompanyFile(folderAndFileDTO));
        return documentDTO;
    }


    //查询文件夹
    private List<DocFolderDTO> queryCompanyFolder(FolderAndFileDTO folderAndFileDTO) {
        Long companyId = UserHolder.getCompanyId();
        QueryWrapper<DocFolder> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocFolder::getParentId, folderAndFileDTO.getParentFoldId());
        queryWrapper.lambda().eq(DocFolder::getCompanyId, companyId);
        List<DocFolder> docFolderList = docFolderService.list(queryWrapper);
        if (!docFolderList.isEmpty()) {
            return BeanHelper.copyWithCollection(docFolderList, DocFolderDTO.class);
        }
        return null;
    }

    /**
     * 查询指定文件夹下 当前移动端用户 可见文档（文档类型为公共读写，公共读，员工自己私有文档）
     *
     * @param folderAndFileDTO
     * @return
     */
    private List<DocFileDTO> queryCompanyFile(FolderAndFileDTO folderAndFileDTO) {
        //1.先把公共读的权限文档查询到
        Long companyId = UserHolder.getCompanyId();
        Long companyUserId = UserHolder.getCompanyUserId();
        QueryWrapper<DocFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocFile::getFolderId, folderAndFileDTO.getParentFoldId());
        queryWrapper.lambda().eq(DocFile::getCompanyId, companyId);
        queryWrapper.lambda().in(DocFile::getAuthority, DocumentEnum.ALL_READ.getAuthority(), DocumentEnum.ALL_READ_WRITE.getAuthority());
        List<DocFile> docFileList = docFileService.list(queryWrapper);

        //2. 查询自己文档私有
        QueryWrapper<DocFile> privateAuthority = new QueryWrapper<>();
        privateAuthority.lambda().eq(DocFile::getFolderId, folderAndFileDTO.getParentFoldId());
        privateAuthority.lambda().eq(DocFile::getCompanyId, companyId);
        privateAuthority.lambda().eq(DocFile::getCompanyUserId, companyUserId);
        List<DocFile> privateFileList = docFileService.list(privateAuthority);


        //3. 其他用户将自己设置为 协作者也能查看文档
        QueryWrapper<Collaborations> collaborationsQueryWrapper = new QueryWrapper<>();
        collaborationsQueryWrapper.lambda().eq(Collaborations::getCompanyUserId, companyUserId);
        List<Collaborations> collaborationsList = collaborationsService.list(collaborationsQueryWrapper);
        List<Long> fileIds = collaborationsList.stream().map(Collaborations::getFileId).collect(Collectors.toList());
        Collection<DocFile> collaborationFileList = docFileService.listByIds(fileIds);
        //判断文档是否属于当前文件夹
        List<DocFile> newCollaborationFileList = collaborationFileList.stream().filter(docFile -> docFile.getFolderId().equals(folderAndFileDTO.getParentFoldId())).collect(Collectors.toList());


        //处理三个集合数据，将相同的文档数据从集合中移除掉
        if (docFileList.isEmpty()) {
            docFileList = new ArrayList<>();
        }
        //将三个集合 合并在一起
        docFileList.addAll(privateFileList);
        docFileList.addAll(newCollaborationFileList);

        //使用        LinkedHashSet 特性进行去重
        List<DocFile> docFiles = new ArrayList<>(new LinkedHashSet<>(docFileList));

        return BeanHelper.copyWithCollection(docFiles, DocFileDTO.class);
    }


    /**
     * 新增文件夹
     *
     * @param folderDTO
     */
    public void save(DocFolderDTO folderDTO) {
        DocFolder folder = BeanHelper.copyProperties(folderDTO, DocFolder.class);
        folder.setCompanyUserId(UserHolder.getCompanyUserId());
        folder.setCompanyId(UserHolder.getCompanyId());
        folder.setStatus(1);
        boolean b = docFolderService.save(folder);
        if (!b) {
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }
    }

    @Transactional
    public void insertFile(DocFileDTO fileDTO) throws UnsupportedEncodingException {
        fileDTO.setCompanyUserId(UserHolder.getCompanyUserId());
        DocFile file = BeanHelper.copyProperties(fileDTO, DocFile.class);
        file.setCompanyId(UserHolder.getCompanyId());
        file.setCompanyUserId(UserHolder.getCompanyUserId());
        file.setEnable(true);
        file.setFileSize(CountUtil.getSize(file.getContent().getBytes("utf-8").length));
        Boolean b = docFileService.save(file);
        if (!b) {
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }
        //保存到历史版本中
        FileHistory fileHistory = new FileHistory();
        fileHistory.setFileId(file.getId());
        fileHistory.setFileName(file.getName());
        fileHistory.setCompanyUserId(file.getCompanyUserId());
        fileHistory.setIfCreate(true);
        fileHistory.setContent(file.getContent());
        Boolean b1 = fileHistoryService.save(fileHistory);
        if (!b) {
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }
    }

    public DocFileDTO queryDocFileById(Long id) {
        DocFile docFile = docFileService.getById(id);
        if (docFile == null) {
            throw new NcException(ResponseEnum.DOC_NOT_FOUND);
        }
        return BeanHelper.copyProperties(docFile, DocFileDTO.class);
    }

    /**
     * 移动端定时保存文件内容
     *
     * @param docFileDTO
     */
    @Transactional
    public void updateFileAuto(DocFileDTO docFileDTO) throws UnsupportedEncodingException {
        //先判断当前用户是否有权限对文档进行编辑
        Boolean aBoolean = checkAuth(docFileDTO);
        if (!aBoolean) {
            throw new NcException(ResponseEnum.FILE_NOT_ALLOWED_MODIFY);
        }

        Long companyUserId = UserHolder.getCompanyUserId();
        DocFile docFile = BeanHelper.copyProperties(docFileDTO, DocFile.class);
        docFile.setUpdateUserId(companyUserId);
        docFile.setFileSize(CountUtil.getSize(docFile.getContent().getBytes("utf-8").length));
        boolean b = docFileService.updateById(docFile);
        if (!b) {
            throw new NcException(ResponseEnum.UPDATE_OPERATION_FAIL);
        }

        //保存到历史版本中
        FileHistory fileHistory = new FileHistory();
        fileHistory.setFileId(docFileDTO.getId());
        fileHistory.setFileName(docFileDTO.getName());
        fileHistory.setCompanyUserId(companyUserId);
        fileHistory.setIfCreate(false);
        fileHistory.setContent(docFileDTO.getContent());
        Boolean b1 = fileHistoryService.save(fileHistory);
        if (!b) {
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }
    }

    public PageResult<CompanyUserDTO> pagingCollaborations(Long fileId, Integer page, Integer pageSize) {
        //根据文档ID 查询协作者表 获取文档协作者用户ID集合
        QueryWrapper<Collaborations> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Collaborations::getFileId, fileId);
        IPage<Collaborations> ipage = collaborationsService.page(new Page<>(page, pageSize), queryWrapper);
        List<Long> companyUserIds = ipage.getRecords().stream().map(Collaborations::getCompanyUserId).collect(Collectors.toList());
        if (!companyUserIds.isEmpty()) {
            //远程调用系统微服务获取用户列表
            List<CompanyUserDTO> companyUserDTOList = companyUserClient.queryCompanyUserByIds(companyUserIds).getData();
            return new PageResult<>(ipage.getTotal(), ipage.getPages(), companyUserDTOList);
        }
        return null;
    }

    /**
     * 返回所有企业员工标识用户类型：作者，协作者，无
     *
     * @param fileId
     * @return
     */
    public List<UserCollaborationDTO> pagingCollaborationUsers(Long fileId) {
        //根据文档ID查询文档对象
        DocFile docFile = docFileService.getById(fileId);
        //根据文档ID查询 文档协作者员工ID集合
        QueryWrapper<Collaborations> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Collaborations::getFileId, fileId);
        List<Long> collaborationCompanyUserIds = collaborationsService.list(queryWrapper).stream().map(Collaborations::getCompanyUserId).collect(Collectors.toList());
        if (docFile == null) {
            throw new NcException(ResponseEnum.DOC_NOT_FOUND);
        }
        //远程调用系统微服务 获取当前企业所有的员工
        List<CompanyUserDTO> companyUserDTOList = companyUserClient.queryCurrentAllQuery().getData();
        if (!companyUserDTOList.isEmpty()) {
            List<UserCollaborationDTO> userCollaborationDTOS = BeanHelper.copyWithCollection(companyUserDTOList, UserCollaborationDTO.class);
            //判断当前用户类型
            for (UserCollaborationDTO userCollaborationDTO : userCollaborationDTOS) {
                int state = docFile.getCompanyUserId().equals(userCollaborationDTO.getId()) ? 1 : collaborationCompanyUserIds.contains(userCollaborationDTO.getId()) ? 2 : 0;
                userCollaborationDTO.setState(state);
            }
            return userCollaborationDTOS;
        }
        return null;
    }

    public void insertCollaboration(CollaborationsDTO collaborationsDTO) {
        Collaborations collaborations = new Collaborations();
        collaborations.setFileId(collaborationsDTO.getFileId());
        collaborations.setCompanyUserId(collaborationsDTO.getUserId());
        boolean b = collaborationsService.save(collaborations);
        if(!b){
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }
    }

    public void deleteCollaboration(CollaborationsDTO collaborationsDTO) {
        //根据协作者员工ID，文档ID进行删除
        QueryWrapper<Collaborations> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Collaborations::getCompanyUserId, collaborationsDTO.getUserId());
        queryWrapper.lambda().eq(Collaborations::getFileId, collaborationsDTO.getFileId());
        boolean b = collaborationsService.remove(queryWrapper);
        if(!b){
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }
    }

    public void updateAuthority(Long fileId, Integer authority) {
        //当前用户是否为文档拥有者
        DocFile docFile = docFileService.getById(fileId);
        if(!docFile.getCompanyUserId().equals(UserHolder.getCompanyUserId())){
            throw new NcException(ResponseEnum.FILE_NOT_BELONG_YOU);
        }
        docFile.setAuthority(authority);
        boolean b = docFileService.updateById(docFile);
        if(!b){
            throw new NcException(ResponseEnum.UPDATE_OPERATION_FAIL);
        }
    }

    @Transactional
    public void updateFile(DocFileDTO fileDTO) {
        //检查是否有权限
        Boolean aBoolean = checkAuth(fileDTO);
        if (!aBoolean) {
            throw new NcException(ResponseEnum.FILE_NOT_ALLOWED_MODIFY);
        }
        //更新文件信息
        DocFile file = BeanHelper.copyProperties(fileDTO, DocFile.class);
        file.setFileSize(CountUtil.getSize(file.getContent().getBytes().length));
        boolean b = docFileService.updateById(file);
        if(!b){
            throw new NcException(ResponseEnum.UPDATE_OPERATION_FAIL);
        }
        //更新文件编辑历史表
        FileHistory fileHistory = new FileHistory();
        fileHistory.setContent(fileDTO.getContent());
        fileHistory.setCompanyUserId(fileDTO.getCompanyUserId());
        fileHistory.setFileId(file.getId());
        fileHistory.setFileName(file.getName());
        fileHistory.setCreateTime(new Date());
        boolean b1 = fileHistoryService.save(fileHistory);
        if(!b1){
            throw new NcException(ResponseEnum.UPDATE_OPERATION_FAIL);
        }
    }

    /**
     * 检查是否有权限进行修改
     *
     * @param fileDTO
     */
    private Boolean checkAuth(DocFileDTO fileDTO) {
        DocFile file = docFileService.getById(fileDTO.getId());
        //公共读写
        if (file.getAuthority() == DocumentEnum.ALL_READ_WRITE.getAuthority()) {
            return true;
        }
        //私有
        if (file.getAuthority() == DocumentEnum.PRIVATE_READ_WRITE.getAuthority() || file.getAuthority() == DocumentEnum.ALL_READ.getAuthority()) {
            //查询当前用户是否为文档拥有者 或者协作者
            if (file.getCompanyUserId() == UserHolder.getCompanyUserId()) {
                return true;
            }
            //查询协作者
            QueryWrapper<Collaborations> collaborationsQueryWrapper = new QueryWrapper<>();
            collaborationsQueryWrapper.lambda().eq(Collaborations::getFileId, fileDTO.getId());
            List<Collaborations> collaborations = collaborationsService.list(collaborationsQueryWrapper);
            for (Collaborations collaboration : collaborations) {
                if (collaboration.getCompanyUserId() == UserHolder.getCompanyUserId()) {
                    return true;
                }
            }
        }
        return false;
    }
}
